#include "db_worker_thread.h"

#include "task_command.h"
#include "task_manager.h"

#include <QString>
#include <utility>

namespace base::tasking {

DbWorkerThread::DbWorkerThread(TaskManager* manager, int index, QObject* parent)
    : QThread(parent)
    , m_manager(manager)
    , m_index(index)
{
    setObjectName(QStringLiteral("DbWorkerThread-%1").arg(index));
}

DbWorkerThread::~DbWorkerThread()
{
    stop();
}

void DbWorkerThread::stop()
{
    m_stopRequested.store(true, std::memory_order_relaxed);
}

void DbWorkerThread::run()
{
    while (!m_stopRequested.load(std::memory_order_relaxed)) {
        if (!m_manager) {
            break;
        }

        auto command = m_manager->takeNextCommand();
        if (!command) {
            if (m_manager->isStopping()) {
                break;
            }
            continue;
        }

        if (command->handle && command->handle->isCanceled()) {
            TaskResult canceledResult = TaskResult::failureResult(
                kernel::ErrorCode::InvalidOperation,
                QStringLiteral("Task canceled before execution"));
            m_manager->onTaskFinished(command, canceledResult);
            continue;
        }

        m_manager->onTaskStarted(command);

        TaskResult result = TaskResult::successResult();
        try {
            if (command->work) {
                result = command->work(command->handle);
            }
        } catch (const std::exception& ex) {
            result = TaskResult::failureResult(kernel::ErrorCode::SystemError, QString::fromUtf8(ex.what()));
        } catch (...) {
            result = TaskResult::failureResult(kernel::ErrorCode::UnknownError,
                                               QStringLiteral("Unknown exception in DbWorkerThread"));
        }

        m_manager->onTaskFinished(command, result);
    }
}

} // namespace base::tasking
